<script setup lang="ts">
/**
 * @name IndicatorTopologicalGraph
 * @description 指标拓扑图
 */
import ConfigTreeOrg from './components/ConfigTreeOrg/ConfigTreeOrg.vue'
import ResponsiveModels from './components/ResponsiveModels/ResponsiveModels.vue'
import { useModelLists } from '@/views/ApplicationModels/ApplicationModels'
import type { ApplicationModel } from '@/types/modules/application-models'
import type { Point } from '@/components/ReadonlyPointTree/ReadonlyPointTree'
import { STORAGE_MODES } from '@/enum/modules/indicator'
import ReadonlyPointTree from '@/components/ReadonlyPointTree/ReadonlyPointTree.vue'

type NodeLists = (Point & {
  color?: string
  data: ApplicationModel['data']
})[]

const treeRef = ref<InstanceType<typeof ReadonlyPointTree>>()
const timeType = ref<STORAGE_MODES | null>(null) as any
const {
  lists: modelLists,
  children,
  loading,
  timeTypeList,
  getLists,
  getChildrenById,
  getIndicatorsTopologicalGraph,
  loadTimeTypeList,

  toApplicationModelConfigs,
  toApplicationModels,
} = useModelLists()

const colors = [
  '#14cccc',
  '#4167f0',
  '#6222c9',
  '#e63415',
  '#ff6600',
  '#ffde0a',
  '#1ec79d',
]
const nodeLists = computed<Point[]>(() => {
  const recursive = (
    array: ApplicationModel[],
    i: number = 0,
  ): Point[] => {
    return array.reduce((acc, cur) => {
      acc.push({
        id: cur.id,
        parentId: cur.parentId,
        pointName: cur.name,
        children:
          cur.children && cur.children.length > 0
            ? recursive(cur.children, i + 1)
            : [],
      })
      return acc
    }, [] as Point[])
  }
  return recursive(unref(children))
})
const [modelId, setModelId] = useState(0)
const [point, setPoint] = useState<Point | null>(null)
const [graphData, setGraphData] = useState<ApplicationModel[]>([])
const [graphLoading, setGraphLoading] = useState(false)

const treeData = computed<NodeLists>(() => {
  const recursive = (
    array: ApplicationModel[],
    i: number = 0,
  ): NodeLists => {
    return array.reduce((acc, cur) => {
      acc.push({
        id: cur.id,
        parentId: cur.parentId,
        pointName: cur.name,
        data: cur.data,
        color: colors[i % colors.length],
        children:
          cur.children && cur.children.length > 0
            ? recursive(cur.children, i + 1)
            : [],
      })
      return acc
    }, [] as NodeLists)
  }
  return recursive(unref(graphData))
})

const isSimple = ref(true)
const allUlExpand = computed(() => {
  return !unref(isSimple)
})

// 实时>日>月>年>小时
function getDefaultTimeType(): STORAGE_MODES | null {
  const tt = unref(timeTypeList)
  const now = tt.find(v => v.value === STORAGE_MODES.NOW)
  if (now)
    return STORAGE_MODES.NOW
  const day = tt.find(v => v.value === STORAGE_MODES.DAY)
  if (day)
    return STORAGE_MODES.DAY
  const month = tt.find(v => v.value === STORAGE_MODES.MONTH)
  if (month)
    return STORAGE_MODES.MONTH
  const year = tt.find(v => v.value === STORAGE_MODES.YEAR)
  if (year)
    return STORAGE_MODES.YEAR
  const hour = tt.find(v => v.value === STORAGE_MODES.HOUR)
  if (hour)
    return STORAGE_MODES.HOUR
  return null
}

watch(
  () => unref(timeType),
  async () => {
    const pointId = unref(point)?.id
    const tt = unref(timeType)
    if (pointId && tt) {
      setGraphLoading(true)
      try {
        const { data } = await (getIndicatorsTopologicalGraph)(tt, pointId)
        setGraphData(data)
        setGraphLoading(false)
      }
      catch (e) {
        console.warn(e)
        setGraphLoading(false)
        setGraphData([])
      }
    }
    else {
      setGraphData([])
    }
  },
)

async function handleClickNode(o: Point) {
  setPoint(o)
}

watchEffect(async () => {
  const pointId = unref(point)?.id
  if (pointId) {
    await loadTimeTypeList(pointId)

    // 切换点位强行刷新时间类型，以便获取到最新的拓扑图数据
    await nextTick()
    timeType.value = null
    await nextTick()
    timeType.value = getDefaultTimeType()
  }
  else {
    // 没有点位时置空timeTypeList
    timeTypeList.value = []
  }
})

provide('allUlExpand', allUlExpand)

watch(
  () => unref(modelId),
  async (mid: number) => {
    if (!mid)
      return
    await getChildrenById(mid)
    await nextTick()
    // 模型切换后强制刷新选择的点位
    setPoint(null)
    await nextTick()
    const head = unref(nodeLists)[0]
    if (head) {
      treeRef.value?.setCurrentKey(
        String(head.id),
      )
      setPoint(head)
    }
  },
)

onMounted(async () => {
  await getLists()
  const mid = unref(modelLists)[0]?.id
  if (mid) {
    setModelId(mid)
  }
})
</script>

<template>
  <div class="padding-sm flex container">
    <div class="flex-direction model-tree-container flex flex-shrink-0">
      <div class="width-fill relative flex-shrink-0">
        <h3 class="!margin-0">
          应用模型
        </h3>
        <div class="special-select align-center flex justify-end">
          <ElSelect v-model="modelId" class="free" placeholder="请选择应用模型">
            <ElOption label="请选择" :value="0" disabled />
            <ElOption v-for="item in modelLists" :key="item.id" :label="item.name" :value="item.id" />
          </ElSelect>
          <ElLink v-if="false" class="margin-left-xs flex-shrink-0" type="primary" @click="toApplicationModels">
            模型管理
          </ElLink>
          <ElLink v-if="false" class="margin-left-xs flex-shrink-0" type="primary" @click="toApplicationModelConfigs">
            模型配置
          </ElLink>
        </div>
        <div v-if="false" class="responsive">
          <ResponsiveModels v-model:model-id="modelId" :show-include-sub-checkbox="false" :data="modelLists" />
        </div>
      </div>
      <div
        v-loading="loading"
        element-loading-custom-class="global-loading"
        class="margin-top-sm flex-fillRemaining points-box"
      >
        <ReadonlyPointTree
          ref="treeRef" :show-title="false" external :points="nodeLists" :default-expand-all="false"
          @click-node="handleClickNode"
        />
      </div>
    </div>
    <div class="margin-left-sm flex-direction flex flex-1">
      <div class="relative flex-shrink-0">
        <h3 class="!margin-0">
          指标拓扑图
        </h3>
        <ElRadioGroup v-if="timeTypeList.length > 0" v-model="timeType" class="time-type">
          <ElRadio v-for="item in timeTypeList" :key="item.value" :value="item.value">
            {{ item.label }}
          </ElRadio>
        </ElRadioGroup>
        <div class="align-center expand-trigger inline-flex">
          <span class="margin-right-sm">精简模式</span>
          <ElSwitch v-model="isSimple" />
        </div>
      </div>
      <div v-if="treeData.length > 0" v-loading="graphLoading" class="flex-fillRemaining margin-top-sm tree-container">
        <div class="tree-wrapper box-border w-full border rounded-sm">
          <ConfigTreeOrg v-if="timeType" :data="treeData[0]" :content-expand="true" :time-type="timeType" />
        </div>
      </div>
      <div v-else class="flex-fillRemaining align-center margin-left-sm flex justify-center">
        <TableEmpty />
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.responsive,
.expand-trigger,
.time-type,
.special-select {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 150px;

  :deep(.el-input) {
    min-width: auto !important;
  }

  :deep(.el-select) {
    flex: 1;
  }
}

.responsive {
  display: none;

  :deep(.el-dropdown) {
    outline: none !important;
  }

  @media screen and (max-width: 1400px) {
    display: block;
    width: auto;
    outline: none;
  }
}

.special-select {
  @media screen and (max-width: 1400px) {
    display: none;
  }
}

.model-tree-container {
  flex-basis: 20%;
  transition: all .3s;

  @media screen and (max-width: 1800px) {
    flex-basis: 23%;
  }
}

.points-box {
  --container-left-width: 100%;
  @include roll();
}

.expand-trigger {
  width: auto;
}

.tree-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  @include roll();

  .box-1 {
    flex: 1;
  }

  .box-3,
  .box-4 {
    flex: 0 0 calc((100% - 20px) / 2);
    height: calc((100% - 20px) / 2);
  }

  .box-3:last-child {
    flex: 100%;
  }

  .box-2 {
    flex: 0 0 calc((100% - 20px) / 2);
    height: 100%;
  }
}

.time-type {
  right: 200px;
  width: auto;
}
</style>
